home *** CD-ROM | disk | FTP | other *** search
- /*
- GrepCompile - routines for compiling patterns into internal form,
- and for matching strings against the compiled pattern.
- */
-
-
- # include <DialogMgr.h>
- # include "Grep.h"
-
- /* special internal chars for compiled pattern */
-
- # define CCL 1 /* match characters in class */
- # define NCCL 2 /* all but characters in class */
- # define CRANGE 3 /* range of chars */
- # define ENDCCL 4 /* end char class */
- # define ANY 5 /* match any char */
- # define CLOSURE 6 /* closure */
- # define EOL 7 /* end of line */
-
-
- /* pattern compilation and matching vars */
-
- static Boolean matchBol; /* match beginning of line? */
- static int pix; /* index into pattern */
- static int pMark;
- static Boolean canClose;
-
- /*
- Pattern buffers. rawPattern is the text typed by user into
- the dialog box. cmpPattern is the compiled pattern. Initially
- they are both empty. (Format of the nil compiled pattern is
- dependent on algorithm used to compile rawPattern.) This is
- legal - it matches every line. If a file is grepped without
- specifying a pattern, therefore, the whole file will be
- displayed. A side effect of this is to turn grep on WORD files
- into a WORD-to-TEXT file converter when the save output option
- is turned on.
- */
-
- char rawPattern[bufSiz] = "";
- static char cmpPattern[bufSiz] = "";
-
-
- /* ----------------------------------------------------------------------- */
- /* pattern-compilation routines */
- /* ----------------------------------------------------------------------- */
-
-
-
- /*
- Add char to pattern (may be a metachar, not necessarily
- a literal character to match)
- */
-
- AddPatChar (c)
- char c;
- {
- if (ignoreCase && c >= 'A' && c <= 'Z')
- c += 'a' - 'A';
- cmpPattern[pix] = c;
- ++pix;
- cmpPattern[pix] = 0;
-
- } /* AddPatChar */
-
-
- /*
- Put a closure indicator into the pattern, in front of the
- stuff that's to be closed.
- */
-
- AddClosure ()
- {
- register int i;
-
- ++pix;
- for (i = pix; i > pMark; --i)
- /*loop (, i = pix, , --i <= pMark)*/
- cmpPattern [i] = cmpPattern [i-1];
- cmpPattern [pMark] = CLOSURE;
- canClose = false;
-
- } /* AddClosure */
-
-
- /*
- have found something that may be followed by a closure. set
- canClose to indicate that fact, and set a mark to remember where
- the closable thing is.
- */
-
- MarkIt ()
- {
- pMark = pix; /* set mark in case closure comes up next */
- canClose = true;
- }
-
-
- /*
- Get escaped char (char following '\'). The only special one
- right now is '\t', which is turned into a tab. Caller must check
- that return value isn't zero.
- */
-
- char EscapeChar (c)
- char c;
- {
- return (c == 't' ? '\t' : c);
- }
-
- /*
- compile character class. pass pointer to char after '[' that begins
- the class pattern. Return nil if (error, else pointer to char
- after closing ']' bracket.
- */
-
- StringPtr Class (p)
- register StringPtr p;
- {
- register char c, type, low, high;
-
- type = CCL; /* 'character class' metachar */
- if (*p == '^')
- {
- type = NCCL; /* 'match all but this class' metachar */
- ++p;
- }
- AddPatChar (type);
- for (;;)
- {
- c = *p;
- ++p;
- if (c == '\\')
- {
- c = EscapeChar (*p);
- ++p;
- }
- else if (c == ']')
- break; /* end of class pattern */
- if (c == 0)
- return (nil); /* missing ']' - pattern error */
- if (*p != '-')
- AddPatChar (c);
- else /* range */
- {
- low = c; /* low end */
- ++p;
- high = *p; /* high end */
- ++p;
- if (high == 0)
- return (nil); /* pattern error */
- AddPatChar (CRANGE);
- AddPatChar (low);
- AddPatChar (high);
- }
- }
- AddPatChar (ENDCCL);
- return (p); /* all ok */
-
- } /* class */
-
-
- /*
- COMPILE - compile string into internal form suitable for efficient
- pattern matching. String should be in C format.
- */
-
- Boolean Compile (p)
- register StringPtr p;
- {
- register char c;
-
- pix = 0;
- cmpPattern[0] = 0;
- canClose = false;
- matchBol = false;
- /*
- check for ^ - it's only special at beginning of line
- */
- if (*p == '^')
- {
- matchBol = true;
- ++p;
- }
- for (;;)
- {
- c = *p;
- ++p;
-
- if (c == '*')
- {
- /*
- if (canClose is true, there was a preceding pattern which can be
- closed (not closure, ^ or $), so close it. otherwise, take *
- literally.
- */
- if (canClose) /* something to close */
- {
- AddClosure ();
- continue;
- }
- }
-
- /*
- $ only special at end of line
- */
- if (c == '$' && *p == 0)
- {
- AddPatChar ((char) EOL);
- continue;
- }
- /*
- at this point we know we have a character that can be followed by a
- closure, so mark the pattern position.
- */
- MarkIt ();
-
- /*
- use most escaped chars literally, except null, which is an error,
- and \t, which is a tab.
- */
- if (c == '\\')
- {
- c = EscapeChar (*p++);
- if (c == 0)
- return (false); /* pattern error */
- AddPatChar (c);
- continue;
- }
- if (c == 0) break; /* done compiling */
- switch (c)
- {
- case '.': AddPatChar (ANY); break; /* match any char */
- case '[': /* match character class */
- {
- if ((p = Class (p)) == nil)
- return (false); /* class pattern error */
- break;
- }
- default: AddPatChar (c); /* match char literally */
- }
-
- } /* loop */
-
- return (true); /* all ok */
-
- } /* compile */
-
-
- /* ----------------------------------------------------------------------- */
- /* pattern-matching routines */
- /* ----------------------------------------------------------------------- */
-
- /*
- NEXTPOS - find position in pattern of next component to match
- */
-
- StringPtr NextPos (p)
- register StringPtr p;
- {
- register char c;
-
- c = *p;
- ++p;
- if (c == CCL || c == NCCL)
- {
- do /* look for end of class stuff */
- {
- c = *p;
- ++p;
- } while (c != ENDCCL);
- }
- return (p);
-
- } /* NextPos */
-
-
- Boolean InClass (c, p)
- register char c;
- register StringPtr p;
- {
- register char high, low, pc;
-
- for (;;)
- {
- pc = *p;
- ++p;
- if (pc == ENDCCL)
- return (false);
- if (pc == CRANGE) /* range */
- {
- low = *p;
- ++p;
- high = *p;
- ++p;
- if (low <= c && c <= high)
- break; /* it's within the range */
- }
- else if (c == pc)
- break; /* it matched this char of class */
- }
- return (true);
-
- } /* InClass */
-
- /*
- OMATCH - match character c against the current pattern position.
- */
-
- Boolean omatch (c, p)
- register char c;
- register StringPtr p;
- {
- register char pc;
-
- if (ignoreCase && c >= 'A' && c <= 'Z')
- c += 'a' - 'A';
- pc = *p;
- ++p;
- switch (pc)
- {
- case CCL: return (InClass (c, p));
- case NCCL: return (!InClass (c, p));
- case ANY: return (c != 0); /* don't match end of line */
- default: return (c == pc);
- }
-
- } /* omatch */
-
-
- /*
- try to match pattern p at the given position in string s
- */
-
- Boolean amatch (s, p)
- register StringPtr s, p;
- {
- register StringPtr cursp;
-
- if (*p == 0)
- return (true); /* end of pattern, have matched it */
- if (*p == EOL)
- return (*s == 0); /* must be end of string to match EOL */
-
- if (*p == CLOSURE)
- {
-
- /*
- advance as far as possible, matching the current pattern position.
- when omatch fails, s will point 1 past the character that failed.
- then back up one and try to match rest of pattern. if that fails,
- keep retreating until back at point of original closure start
- */
-
- ++p; /* skip closure marker */
- cursp = s; /* save current string position */
-
- while (omatch (*s++, p))
- /* march! */ ;
-
- do /* keep backing up */
- {
- --s;
- if (amatch (s, NextPos (p)))
- return (true);
- } while (s > cursp);
- return (false);
- }
-
- if (omatch (*s++, p))
- return (amatch (s, NextPos (p)));
- return (false);
-
- } /* amatch */
-
-
- /*
- MATCH - match string s against the compiled pattern
-
- if matchBol is true, then anchor the match to the beginning of the
- string, else try the pattern against successive string positions until
- the match succeeds or the end of the string is reached.
-
- s should be in C format.
- */
-
- Boolean match (s)
- register StringPtr s;
- {
- if (matchBol) /* anchored match */
- {
- return (amatch (s, cmpPattern));
- }
- for (;;) /* floating match */
- {
- if (amatch (s, cmpPattern))
- return (true);
- if (*s == 0)
- return (false); /* end of string but no match */
- ++s;
- }
-
- } /* match */
-
-
- /*
- Routines for presenting the pattern entry dialog.
- */
-
-
- /*
- pattern dialog items
-
- item type
- 1 ok button
- 2 cancel button
- 3 prompt
- 4 edittext item for typing in pattern
- 5 "lines not containing pattern" radio button
- 6 "print line numbers" check box
- 7 "ignore case" check box
-
- Puts the string entered into theString, which on return is
- empty if either the user clicked Cancel or typed no string
- and clicked ok.
- */
-
- enum
- {
- okButton = 1,
- cancelButton,
- promptStatText,
- patText,
- lineOption,
- numberOption,
- caseOption
- };
-
-
- static DialogPtr theDialog;
-
-
-
- /*
- Set or get the value of a checkbox (i.e., boolean) dialog item
- */
-
- SetDBoolean (itemNo, itemValue)
- int itemNo;
- Boolean itemValue;
- {
- Handle itemHandle;
- int itemType;
- Rect r;
-
- GetDItem (theDialog, itemNo, &itemType, &itemHandle, &r);
- /*
- Note type conversion here. True turns the control on.
- */
- SetCtlValue (itemHandle, (int) itemValue);
- }
-
-
- Boolean GetDBoolean (itemNo)
- int itemNo;
- {
- Handle itemHandle;
- int itemType;
- Rect r;
-
- GetDItem (theDialog, itemNo, &itemType, &itemHandle, &r);
- return ((Boolean) GetCtlValue (itemHandle));
- }
-
-
- Boolean GetPatDlog ()
- {
- int itemNo, itemType;
- Handle itemHandle;
- Rect r;
- register Boolean result;
-
- theDialog = GetNewDialog (resBase + patBox, nil, -1L);
- SetDBoolean (lineOption, !prtMatches);
- SetDBoolean (numberOption, prtLineNum);
- SetDBoolean (caseOption, ignoreCase);
- GetDItem (theDialog, patText, &itemType, &itemHandle, &r);
- SetIText (itemHandle, rawPattern);
- SelIText (theDialog, patText, 0, 32760);
- ShowWindow (theDialog);
- for (;;)
- {
- ModalDialog (nil, &itemNo);
- if (itemNo == cancelButton)
- {
- result = false;
- break;
- }
- else if (itemNo == okButton)
- {
- GetDItem (theDialog, patText, &itemType, &itemHandle, &r);
- GetIText (itemHandle, rawPattern);
- prtMatches = !GetDBoolean (lineOption);
- prtLineNum = GetDBoolean (numberOption);
- ignoreCase = GetDBoolean (caseOption);
- result = true;
- break;
- }
- else /* must be option check box - flip value */
- {
- SetDBoolean (itemNo, !GetDBoolean (itemNo));
- }
- }
-
- DisposDialog (theDialog);
- return (result);
-
- } /* GetPatDlog */
-
-
- GetGrepPat ()
- {
- if (GetPatDlog ())
- {
- PtoCstr (rawPattern);
- havePat = Compile (rawPattern);
- CtoPstr (rawPattern);
- if (!havePat)
- Alarm ("\pBad Pattern");
- }
- }
-